/*
 * CPISender.cpp
 *
 *  Created on: 2013. 12. 3.
 *      Author: mega
 */

#include "CPISender.h"

#include <curl/curl.h>
#include <json/json.h>
#include <Dispatcher/Static.h>
#include <sstream>

#include "../macro.h"

namespace ProjectZ { namespace NProcess {

CPISender::CPISender() : _clsThreadPool(1)
{
	_request_addr = "http://advance-service.gamevil.com/gv_request_gift_vc";
	_confirm_addr = "http://advance-service.gamevil.com/gv_confirm_vc";
}

CPISender::~CPISender()
{

}

void
CPISender::Push(Param & param)
{

	{
		std::lock_guard<std::mutex> lock(_mutex);
		_clsParamVector.push_back(param);
	}
	_clsThreadPool.PostTask(std::bind(&CPISender::work, this));
}

void
CPISender::work()
{
	Param param;

	while (true)
	{
		{
			std::lock_guard<std::mutex> lock(_mutex);
			if (_clsParamVector.size() <= 0 )
				break;

			param = _clsParamVector.front();
			_clsParamVector.pop_front();
		}

		DEBUGLOG("CPISender : Request Json = %s", param._json.c_str());

		CPIGIFTMAP giftMap;

		if (false == RequestJSONParse(giftMap, param._json))
		{
			OnEvent(param._user, -1);
			continue;
		}

		//if (false == SendCPIRequest(param._json, param._user))
		if (false == SendCPIRequest(param))
		{
			OnEvent(param._user, -1);
			continue;
		}

		SendCPIConfirm(param);

		int reward = 0;

		if (false == ResponseJSONParse(param, giftMap, reward))
		{
			OnEvent(param._user, -1);
			continue;
		}

		OnEvent(param._user, reward);
	}
}

//bool
//CPISender::SendCPIRequest(std::string & json, User * pUser)
//{
//	json_object* jobj = json_tokener_parse(json.c_str());
//
//	stringstream strStream;
//	strStream << pUser->GetUserSeq();
//
//	json_object *jstr = json_object_new_string(strStream.str().c_str());
//	json_object_object_add(jobj, "game_account", jstr );
//
//	std::string send_json = json_object_to_json_string(jobj);
//
//	CURL * curl_ = curl_easy_init();
//
//	char * encodeData = curl_easy_escape(curl_, send_json.c_str(), send_json.length());
//
//	Toolkit::Str<8192> url;
//	url.Format("%s?put=%s", _request_addr.c_str(), encodeData);
//
//	curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
//	curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, CPICallBack);
//	curl_easy_setopt(curl_, CURLOPT_WRITEDATA, this);
//
//	CURLcode res = curl_easy_perform(curl_);
//
//	if (CURLE_OK != res)
//	{
//		curl_easy_cleanup(curl_);
//		PROCESSLOG("SendCPIRequest : CURL Error!! res(%d)", res);
//		return false;
//	}
//
//	curl_easy_cleanup(curl_);
//
//	return true;
//}

bool
CPISender::SendCPIRequest(Param & clsParam)
{
	json_object* jobj = json_tokener_parse(clsParam._json.c_str());

	stringstream strStream;
	strStream << clsParam._user->GetUserSeq();

	json_object *jstr = json_object_new_string(strStream.str().c_str());
	json_object_object_add(jobj, "game_account", jstr );

	std::string send_json = json_object_to_json_string(jobj);

	CURL * curl_ = curl_easy_init();

	char * encodeData = curl_easy_escape(curl_, send_json.c_str(), send_json.length());

	Toolkit::Str<8192> url;
	url.Format("%s?put=%s", _request_addr.c_str(), encodeData);

	curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
	curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, CPICallBack_2);
	curl_easy_setopt(curl_, CURLOPT_WRITEDATA, (void *)& clsParam);

	CURLcode res = curl_easy_perform(curl_);

	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl_);
		PROCESSLOG("SendCPIRequest : CURL Error!! res(%d)", res);
		return false;
	}

	curl_easy_cleanup(curl_);

	return true;
}

//size_t
//CPISender::CPICallBack(void *ptr, size_t size, size_t nmemb, void *arg)
//{
//	return 0;
//#if 0
//	const size_t byte_size_of_ptr = size * nmemb;
//	CPISender * self = (CPISender *)arg;
//	self->_result = (const char *)ptr;
//	return byte_size_of_ptr;
//#endif
//}

size_t
CPISender::CPICallBack_2(void *ptr, size_t size, size_t nmemb, void *arg)
{
	const size_t byte_size_of_ptr = size * nmemb;
	Param * pParam = (Param *)arg;
	pParam->_result = (const char *)ptr;
	return byte_size_of_ptr;
}

void
CPISender::SendCPIConfirm(Param & clsParam)
{
	CURL * curl_ = curl_easy_init();

	char * encodeData = curl_easy_escape(curl_, clsParam._result.c_str(), clsParam._result.length());

	Toolkit::Str<8192> url;
	url.Format("%s?put=%s", _confirm_addr.c_str(), encodeData);

	curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
//	curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, CPICallBack);
//	curl_easy_setopt(curl_, CURLOPT_WRITEDATA, this);

	CURLcode res = curl_easy_perform(curl_);

	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl_);
		PROCESSLOG("SendCPIConfirm : CURL Error!! res(%d)", res);
		return;
	}

	curl_easy_cleanup(curl_);
}

bool
CPISender::RequestJSONParse(CPIGIFTMAP & giftMap, std::string & json)
{
	json_object* jobj = json_tokener_parse(json.c_str());
	if (true == is_error(jobj))
	{
		DEBUGLOG("RequestJSONParse : JSON Parse Error!! json = %s", json.c_str());
		return false;
	}

	json_type jtype = json_object_get_type(jobj);
	if (jtype != json_type_object)
	{
		DEBUGLOG("RequestJSONParse : INVALID JSON Type!! json = %s", json.c_str());
		return false;
	}

	json_object * jgift = json_object_object_get(jobj, "gift");
	if (NULL == jgift)
	{
		DEBUGLOG("RequestJSONParse : Gift is Not Found!! json = %s", json.c_str());
		return false;
	}

	json_type jarray = json_object_get_type(jgift);
	if (jarray != json_type_array)
	{
		DEBUGLOG("RequestJSONParse : Gift is Not Array!! json = %s", json.c_str());
		return false;
	}

	for (int i = 0; i < json_object_array_length(jgift); i++)
	{
		json_object * jobj = json_object_array_get_idx(jgift, i);
		json_object * jvalue = json_object_object_get(jobj, "value");
		json_object * jseq	= json_object_object_get(jobj, "sequence");
		json_object * jname = json_object_object_get(jobj, "name");

		std::string vcType = json_object_get_string(jname);
		std::string sequence = json_object_get_string(jseq);
		std::string value = json_object_get_string(jvalue);

		DEBUGLOG("RequestJSONParse : sequence = %s, vctype = %s, value = %s", sequence.c_str(), vcType.c_str(), value.c_str());

		auto iter = giftMap.find(sequence);

		if (iter == giftMap.end())
		{
			giftMap[sequence] = 0;
		}

		if ("VC1" == vcType)
		{
			giftMap[sequence] += atoi(value.c_str());
		}
	}

	return true;




//    rapidjson::Document document;
//    document.Parse<0>(json.c_str());
//
//    if (true == document.HasParseError())
//    {
//    	PROCESSLOG("RequestJSONParse : JSON Parse Error!! json = %s", json.c_str());
//    	return false;
//    }
//
//    if (false == document.HasMember("gift"))
//    {
//    	PROCESSLOG("RequestJSONParse : Gift is Not Found!! json = %s", json.c_str());
//    	return false;
//    }
//
//    rapidjson::Value & gift_array = document["gift"];
//
//    if (false == gift_array.IsArray())
//    {
//    	PROCESSLOG("RequestJSONParse : Gift is Not Array!! json = %s", json.c_str());
//    	return false;
//    }
//
//    for (int i = 0; i < static_cast<int>(gift_array.Size()); i++)
//    {
//		std::string vcType = gift_array[rapidjson::SizeType(i)]["name"].GetString();
//		std::string sequence = gift_array[rapidjson::SizeType(i)]["sequence"].GetString();
//		std::string value = gift_array[rapidjson::SizeType(i)]["value"].GetString();
//
//		DEBUGLOG("RequestJSONParse : sequence = %s, vctype = %s, value = %s", sequence.c_str(), vcType.c_str(), value.c_str());
//
//		auto iter = giftMap.find(sequence);
//
//		if (iter == giftMap.end())
//		{
//			giftMap[sequence] = 0;
//		}
//
//		if ("VC1" == vcType)
//		{
//			giftMap[sequence] += atoi(value.c_str());
//		}
//    }
//
//    return true;
}

bool
CPISender::ResponseJSONParse(Param & clsParam,CPIGIFTMAP & giftMap, int & reward)
{
	DEBUGLOG("ResponseJSONParse : Result Json = %s", clsParam._result.c_str());

	json_object* jobj = json_tokener_parse(clsParam._result.c_str());
	if (true == is_error(jobj))
	{
		DEBUGLOG("ResponseJSONParse : JSON Parse Error!! json = %s", clsParam._result.c_str());
		return false;
	}

	json_type jtype = json_object_get_type(jobj);
	if (jtype != json_type_object)
	{
		DEBUGLOG("ResponseJSONParse : INVALID JSON Type!!! json = %s", clsParam._result.c_str());
		return false;
	}

	json_object * jgift = json_object_object_get(jobj, "gift");
	if (NULL == jgift)
	{
		DEBUGLOG("ResponseJSONParse : Gift is Not Found!! json = %s", clsParam._result.c_str());
		return false;
	}

	json_type jarray = json_object_get_type(jgift);
	if (jarray != json_type_array)
	{
		DEBUGLOG("ResponseJSONParse : Gift is Not Array!! json = %s", clsParam._result.c_str());
		return false;
	}

	for (int i = 0; i < json_object_array_length(jgift); i++)
	{
		json_object * jobj = json_object_array_get_idx(jgift, i);
		json_object * jseq	= json_object_object_get(jobj, "sequence");

		std::string sequence = json_object_get_string(jseq);

		auto iter = giftMap.find(sequence);

		if (iter == giftMap.end())
			continue;

		reward += iter->second;

		DEBUGLOG("ResponseJSONParse : sequence = %s", sequence.c_str());
	}

	return true;

//    rapidjson::Document document;
//    document.Parse<0>(_result.c_str());
//
//    if (true == document.HasParseError())
//    {
//    	PROCESSLOG("ResponseJSONParse : JSON Parse Error!! json = %s", _result.c_str());
//    	return false;
//    }
//
//    if (false == document.HasMember("gift"))
//    {
//    	PROCESSLOG("ResponseJSONParse : Gift is Not Found!! json = %s", _result.c_str());
//    	return false;
//    }
//
//    rapidjson::Value & gift_array = document["gift"];
//
//    if (false == gift_array.IsArray())
//    {
//    	PROCESSLOG("ResponseJSONParse : Gift is Not Array!! json = %s", _result.c_str());
//    	return false;
//    }
//
//    for (int i = 0; i < static_cast<int>(gift_array.Size()); i++)
//    {
//    	std::string sequence = gift_array[rapidjson::SizeType(i)]["sequence"].GetString();
//
//    	auto iter = giftMap.find(sequence);
//
//    	if (iter == giftMap.end())
//    		continue;
//
//    	reward += iter->second;
//
//		DEBUGLOG("ResponseJSONParse : sequence = %s", sequence.c_str());
//    }
//
//    DEBUGLOG("ResponseJSONParse : Reward = %d", reward);
//
//    return true;
}

void
CPISender::OnEvent(User * pUser, int reward)
{
	pUser->SetCPIReward(reward);
	::Dispatcher::Static::InstancePtr()->GetHandler()->OnCPIEvent(pUser);
}

} /*NProcess*/ } /*ProjectZ*/


